home *** CD-ROM | disk | FTP | other *** search
- #include <stdio.h>
- #include <stdlib.h>
- #include <setjmp.h>
- #include <iocslib.h>
- #include <doslib.h>
- #include <math.h>
- #include <time.h>
- #include "complex.h"
-
- #define USAGE "\
- 3次方程式のジュリア集合を描く\n\
- 使用法: julia3 [reMin imMax scLen [scSize [mxCnt [rot_f_limit [Re_A Im_A [Re_B Im_B [Re_C Im_C]]]]]]]\n\
- Newton法の初期値について reMin=実部最小[-2.0], imMax=虚部最大[2.0], scLen=辺の長さ[4.0]\n\
- scSize=画面サイズ(0…256×256ドット, 1…512×512ドット)[0]\n\
- mxCnt=回数制限(1~65535)[256]\n\
- rot_f_limit=収束半径(収束したと判断する|f(z)|の上限)[0.01]\n\
- Re_A=2次の係数の実部[0.0], Im_A=2次の係数の虚部[0.0]\n\
- Re_B=1次の係数の実部[0.0], Im_B=1次の係数の虚部[0.0]\n\
- Re_C=定数項の実部[-1.0], Im_C=定数項の虚部[0.0]\n\
- f(z)=z^3+A*z^2+B*z+C\n\
- "
-
- /* 画面サイズのデフォルト */
- #define SC_SIZE 0
-
- /* 計算範囲のデフォルト */
- #define RE_MIN (-2.0)
- #define IM_MAX (2.0)
- #define SC_LEN (4.0)
-
- /* 最大ループ回数のデフォルト */
- #define MX_CNT 256
-
- /* 収束判定の制度 */
- #define ROT_F_LIMIT (0.01)
-
- /* キーチェック */
- #define keysns() \
- ({ \
- int _k_ = 0; \
- while (B_KEYSNS()) _k_ = B_KEYINP() & 0xff ? : _k_; \
- _k_; \
- })
-
- double reMin = RE_MIN, imMax= IM_MAX;
- double scLen = SC_LEN;
- int scSize = SC_SIZE;
- int mxCnt = MX_CNT;
- double rot_f_limit = ROT_F_LIMIT;
- double rot_f_limit2;
-
- unsigned short *paTable; /* パレットテーブル */
-
- void make_palet_table(void); /* パレットテーブルを作る */
- void init_screen(void); /* 画面の初期化 */
- void tini_screen(void); /* 画面の後始末 */
-
- /* 係数と定数項のデフォルト */
- #define Re_A (0.0)
- #define Im_A (0.0)
- #define Re_B (0.0)
- #define Im_B (0.0)
- #define Re_C (-1.0)
- #define Im_C (0.0)
-
- /* 係数と定数項 */
- complex A, B, C;
-
- /* f(z),df_f(z)を変更することで別のジュリア集合を描くことができる */
- /* f(z)=z^3+A*z^2+B*z+C, df_f(z)=3*z^2+2*A*z+B */
- /* マクロ版と関数版のどちらか速い方を選択する */
- #if 0
- #define f(z) cadd(cadd(cadd(cpow3(z), cmul(cpow2(z), A)), cmul((z), B)), C)
- #define df_f(z) cadd(cadd(cremul(cpow2(z), 3.0), cremul(cmul((z), A), 2.0)), B)
- #else
- complex f(complex z)
- {
- return cadd(cadd(cadd(cpow3(z), cmul(cpow2(z), A)), cmul(z, B)), C);
- }
- complex df_f(complex z)
- {
- return cadd(cadd(cremul(cpow2(z), 3.0), cremul(cmul(z, A), 2.0)), B);
- }
- #endif
-
- /* 初期値cでf(z)に対するNewton法の漸化式の反復回数を返す */
- int iteration(complex c, int limit_cnt)
- {
- complex z;
- int cnt;
-
- if (setjmp(cjmpenv)) {
- return limit_cnt; /* 計算できなかった */
- }
- cnt = limit_cnt;
- z = c;
- while (cnt > 0 && cabs2(f(z)) > rot_f_limit2) {
- /* f(z)に対するNewton法の漸化式 rec_f(z)=z-f(z)/df_f(z) */
- z = csub(z, cdiv(f(z), df_f(z)));
- cnt--;
- }
- return limit_cnt - cnt;
- }
-
- /* 描画ルーチンの本体 */
- void draw_body()
- {
- unsigned short *a;
- complex c;
- double step;
- unsigned short scCnt;
- unsigned short reCnt;
- unsigned short imCnt;
- complex c0;
-
- scCnt = (scSize ? 512 : 256);
- step = scLen / (double)scCnt;
-
- /* VRAMの書き込みアドレス */
- a = (unsigned short *)0xc00000;
-
- c0 = tocomplex(reMin, imMax);
-
- /* 虚軸方向のループ */
- for (imCnt = 0; imCnt < scCnt; imCnt++) {
- {
- unsigned short *b;
- b = a;
- /* これから描画するラスタを示すための点線を描く */
- for (reCnt = 0; reCnt < 512; reCnt += 8) {
- *b = 0xffff;
- b += 8;
- }
- }
-
- c = c0;
-
- /* 解像度に応じて実軸方向のループ全体を分ける */
- if (scSize == 0) {
- /* 256×256ドット */
-
- /* 実軸方向のループ */
- for (reCnt = 0; reCnt < scCnt; reCnt++) {
- unsigned short col;
-
- /* 漸化式の反復回数を数えてパレットテーブルを参照する */
- col = paTable[iteration(c, mxCnt)];
-
- /* 解像度に応じた大きさの点をVRAMに書き込む */
- *a++ = col;
- *a++ = col;
- a[512-2] = col;
- a[512-1] = col;
-
- /* 実軸方向に進む */
- Re(c) += step;
- }
- } else {
- /* 512×512ドット */
-
- /* 実軸方向のループ */
- for (reCnt = 0; reCnt < scCnt; reCnt++) {
- /* 漸化式の反復回数を数えてパレットテーブルを参照する */
- /* 解像度に応じた大きさの点をVRAMに書き込む */
- *a++ = paTable[iteration(c, mxCnt)];
-
- /* 実軸方向に進む */
- Re(c) += step;
- }
- }
-
- /* 解像度に応じてVRAMの書き込みアドレスを補正する */
- if (scSize == 0) {
- a += 512;
- }
-
- /* 虚軸方向に進む */
- Im(c0) -= step;
-
- /* キーが押されたら中止 */
- if (keysns()) {
- break;
- }
- }
- }
-
- void main(int argc, char *argv[])
- {
- clock_t tm0, tm1;
-
- /* 画面の初期化 */
- init_screen();
-
- /* 係数と定数項のデフォルトを設定 */
- A = tocomplex(Re_A, Im_A);
- B = tocomplex(Re_B, Im_B);
- C = tocomplex(Re_C, Im_C);
-
- /* コマンドラインのパラメータを取得 */
- switch (argc) {
- case 13:
- sscanf(argv[12], "%lf", &Im(C));
- sscanf(argv[11], "%lf", &Re(C));
- case 11:
- sscanf(argv[10], "%lf", &Im(B));
- sscanf(argv[9], "%lf", &Re(B));
- case 9:
- sscanf(argv[8], "%lf", &Im(A));
- sscanf(argv[7], "%lf", &Re(A));
- case 7:
- sscanf(argv[6], "%lf", &rot_f_limit);
- case 6:
- sscanf(argv[5], "%d", &mxCnt);
- case 5:
- sscanf(argv[4], "%d", &scSize);
- case 4:
- sscanf(argv[3], "%lf", &scLen);
- sscanf(argv[2], "%lf", &imMax);
- sscanf(argv[1], "%lf", &reMin);
- case 1:
- break;
- default:
- printf(USAGE);
- return;
- }
-
- /* 収束半径を2乗しておく */
- rot_f_limit2 = rot_f_limit * rot_f_limit;
-
- /* パレットテーブルを作る */
- make_palet_table();
-
- /* VRAMに直接書き込むためにスーパーバイザモードにする */
- B_SUPER(0);
-
- /* 計測開始 */
- {
- clock_t t = clock();
- while ((tm0 = clock()) == t);
- }
-
- /* 描画ルーチンの本体 */
- draw_body();
-
- /* 計測終了 */
- tm1 = clock();
-
- /* 画面の後始末 */
- tini_screen();
-
- /* 所要時間を表示 */
- printf("所要時間は %.8g 秒です.\n", ((double)(tm1 - tm0)) / CLK_TCK);
- }
-